import { pushTarget, popTarget } from './dep.js'
import { queueWatcher } from './schedular.js'

let id = 0
class Watcher {
  constructor(vm, exprOrFn, callback, options) {
    this.vm = vm
    this.callback = callback
    this.options = options
    this.sync = options.sync
    this.user = options.user  // 用户标识watcher类型
    this.id = id++
    this.lazy = options.lazy
    this.dirty = this.lazy

    if(typeof exprOrFn === 'function') {
      this.getter = exprOrFn
    }else{
      // 有可能是  a.b.c 这样的写法
      // 当前 getter 一调用就会去当前实例上面取值
      this.getter = () => {
        let path = exprOrFn.split('.')
        let val = vm
        for(let i = 0; i<path.length;i++) {
          val = val[path[i]]
        }
        return val
      }
    }

    this.depsId = new Set()
    this.deps = []
    this.value = this.lazy ? undefined : this.get()  // 获取老值
  }

  get() {
    // 把watcher存起来 依赖收集
    pushTarget(this)
    let val = this.getter.call(this.vm)  // 渲染watcher执行
    popTarget() // 移除watcher
    return val
  }
  evaluate() {
    this.value = this.get()
    this.dirty = false
  }
  update() {
    // 是否是同步watcher
    if(this.options.sync) {
      this.run()
    }else if(this.lazy) {
      // 计算属性依赖的值发生了改变
      this.dirty = true
    }else{
      // 等待着一起更新   都放入了watcher 
      queueWatcher(this)
    }
    
  }

  addDep(dep) { // watcher 里面不能放重复的dep  dep里面不能放重复的watcher
    let id = dep.id
    if(!this.depsId.has(id)) {
      this.depsId.add(id)
      this.deps.push(dep)
      dep.addSub(this)
    }
  }

  run() {
    // 更新的时候
    let oldValue = this.value; // 
    let newValue = this.get()
    this.value = newValue // 更新老值

    if(this.user) {  // 用户watcher 调用callback
      this.callback.call(this.vm, newValue, oldValue)
    }
  }
}


export default Watcher